WPF/C#:让绘制的图形可以被选中并将信息显示在ListBox中

WPF/C#:让绘制的图形可以被选中并将信息显示在ListBox中

完成的作用

假如你对此感兴趣,能够接着往下阅读。

完成进程

制作矩形

比如说我想制作一个3行4列的表格:

 private void Button_Click_DrawRect(object sender, RoutedEventArgs e)
 {
   int Row = 3;
   int Col = 4;
   
   for(int i = 0; i < Row; i++)
   {
     for(int j = 0; j< Col; j++) 
     {
       // 增加矩形
       System.Windows.Shapes.Rectangle rectangle = new System.Windows.Shapes.Rectangle
       {
         Width = 50,
         Height = 50,
         Stroke = System.Windows.Media.Brushes.Blue,
​
         // 设置填充色彩为通明色
         Fill = System.Windows.Media.Brushes.Transparent,
         StrokeThickness = 1
       };
     
       Canvas.SetLeft(rectangle, 80 + 50 * j);
       Canvas.SetTop(rectangle, 50 + 50 * i);
      
       myCanvas1.Children.Add(rectangle);
      
     }
    
    
   }

完成的作用:

WPF/C#:让制作的图形能够被选中并将信息显现在ListBox中

现在又想画4行3列的表格了,只需修正这里:

int Row = 4;
int Col = 3;

完成的作用:

WPF/C#:让制作的图形能够被选中并将信息显现在ListBox中

为每个单元格增加信息

制作了单元格之后,咱们想要在单元格中增加它地点的行与列的信息。

在制作矩形后边增加:

 // 在矩形内部增加文字
 TextBlock textBlock = new TextBlock
 {
   Text = i + "-" + j,
   Foreground = System.Windows.Media.Brushes.Black,
   FontSize = 12
 };
​
 Canvas.SetLeft(textBlock, 80 + 50 * j + 10);
 Canvas.SetTop(textBlock, 50 + 50 * i + 10);
​
 myCanvas1.Children.Add(textBlock);

现在完成的作用如下所示:

WPF/C#:让制作的图形能够被选中并将信息显现在ListBox中

让每个单元格能够被选中与撤销选中

咱们设定鼠标左键点击表明选中,鼠标右键点击表明撤销选中,选中之后,单元格边框会变红,撤销选中后又康复本来的色彩。

为每个单元格增加鼠标点击事情处理程序:

 // 增加鼠标事情处理器,左键点击表明选中
 rectangle.MouseLeftButtonDown += Rectangle_MouseLeftButtonDown;
​
 // 增加鼠标事情处理器,右键点击表明撤销选中
 rectangle.MouseRightButtonDown += Rectangle_MouseRightButtonDown;

鼠标点击事情处理程序:

 // 鼠标事情处理程序,左键点击表明选中
 private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 {  
   System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
   if (rectangle != null)
   {
     // 改动矩形的色彩以表明它被选中
     rectangle.Stroke = System.Windows.Media.Brushes.Red;       
   }
 }
​
 // 鼠标事情处理器,右键点击表明选中
 private void Rectangle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
  {  
   System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
   if (rectangle != null)
    {
     // 改动矩形的色彩以表明它被撤销选中
     rectangle.Stroke = System.Windows.Media.Brushes.Blue;
           
    }
  }

现在查看完成的作用:

将每个单元格与其间的信息对应起来

在这里能够发现每个单元格与其间的信息是一一对应的联系,咱们就能够选用字典这种数据结构。

Dictionary<System.Windows.Shapes.Rectangle, string> rectangleText = new Dictionary<System.Windows.Shapes.Rectangle, string>();
 // 将单元格与对应的信息存入字典
 rectangleText[rectangle] = textBlock.Text;

这样就完成了每个单元格与其间信息的一一对应。

ListBox的运用

首先规划两个类。

public class SelectedRect
{   
  public string? Name { get; set; }
}

表明选中的单元格,只有一个特点便是它所存储的信息。

public class SelectedRects : ObservableCollection<SelectedRect>
{
​
}

表明选中的多个单元格,承继自ObservableCollection<SelectedRect>

ObservableCollection<T>是.NET结构中的一个类,它表明一个动态数据调集,当增加、删除项或许刷新整个列表时,它会供给通知。这对于数据绑定十分有用,由于当调集改动时,UI能够自动更新以反映这些更改。

 SelectedRects selectedRects;
 public Drawing()
 {
   InitializeComponent();
   this.selectedRects = new SelectedRects();
   DataContext = selectedRects;
​
 }

WPF(Windows Presentation Foundation)中,DataContext是一个十分重要的概念,它是数据绑定的根底。 DataContext是界说在FrameworkElement类中的一个特点,简直一切的WPF控件都承继自FrameworkElement,因此简直一切的WPF控件都有DataContext特点。 DataContext特点通常被设置为一个目标,这个目标包括了绑定到界面元素的数据。当你在XAML中创立数据绑守时,绑定表达式会查找DataContext中的特点。

需求留意的是,DataContext是能够承继的,假如一个元素的DataContext没有被显式设置,它将运用其父元素的DataContext。这使得你能够在窗口等级设置DataContext,然后在窗口的一切子元素中运用数据绑定。

在这里咱们便是这样设置了窗口的DataContext特点为selectedRects

现在咱们修正点击事情处理程序:

 private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 {
   System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
   if (rectangle != null)
   {
     // 改动矩形的色彩以表明它被选中
     rectangle.Stroke = System.Windows.Media.Brushes.Red;
     
     string text = rectangleText[rectangle];
     
     SelectedRect selectedRect = new SelectedRect();
     selectedRect.Name = text;
     selectedRects.Add(selectedRect);
    
   }
​
 }
​
 private void Rectangle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
 {
   System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
   if (rectangle != null)
   {
     // 改动矩形的色彩以表明它被撤销选中
     rectangle.Stroke = System.Windows.Media.Brushes.Blue;
     
     string text = rectangleText[rectangle];
     
     var selectedRect = selectedRects.Where(x => x.Name == text).FirstOrDefault();
     if (selectedRect != null)
     {
       selectedRects.Remove(selectedRect);
     }
​
​
   }
​
 }

在ListBox设置数据绑定:

 <ListBox Grid.Column="1" SelectedIndex="0" Margin="10,0,10,0"
      ItemsSource="{Binding}">
  
 </ListBox>

现在来看看作用:

WPF/C#:让制作的图形能够被选中并将信息显现在ListBox中

咱们会发现在ListBox中只会显现类名,并不会显现类中的信息。

这是为什么呢?

由于咱们只设置了数据绑定,ListBox知道它的数据来自哪里了,可是咱们没有设置数据模板,ListBox不知道该按怎样的方法显现数据。

数据模板的运用

现在咱们就来设置一下数据模板,先来介绍一下数据模板。

WPF(Windows Presentation Foundation)中,数据模板(DataTemplate)是一种界说数据视觉表明的方法。它答应你自界说如何显现绑定到控件的数据。

数据模板十分强大,它能够包括任何类型的元素,并能够运用复杂的绑定和款式。经过运用数据模板,你能够创立丰厚和个性化的UI,而无需在代码中手动创立和办理元素。

现在开端尝试去运用数据模板吧。

在xaml中增加:

<Window.Resources>
  <DataTemplate x:Key="MyTemplate">
    <TextBlock Text="{Binding Path=Name}"/>
  </DataTemplate>
</Window.Resources>

<Window.Resources>:这是一个资源字典,它包括了在整个窗口中都能够运用的资源。在这个比如中,它包括了一个数据模板。 <DataTemplate x:Key="MyTemplate">:这界说了一个数据模板,并给它指定了一个键”MyTemplate”。这个键能够用来在其他地方引证这个模板。 <TextBlock Text="{Binding Path=Name}"/>:这是数据模板的内容。它是一个TextBlock,其Text特点绑定到数据目标的Name特点。{Binding Path=Name}是一个绑定表达式,它告诉WPF查找数据目标中名为Name的特点,并将其值绑定到TextBlock的Text特点。

ListBox运用这个数据模板:

<ListBox Grid.Column="1" SelectedIndex="0" Margin="10,0,10,0"
     ItemsSource="{Binding}"
     ItemTemplate="{StaticResource MyTemplate}">
  
</ListBox>

现在再来看一下作用:

发现能够正常显现数据了,可是还有一个问题,便是会重复增加,最终解决这个问题就好了!

修正鼠标左键点击事情处理程序:

 // 鼠标事情处理器,左键点击表明选中
 private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 {
   System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
   if (rectangle != null)
   {
     // 改动矩形的色彩以表明它被选中
     rectangle.Stroke = System.Windows.Media.Brushes.Red;
     string text = rectangleText[rectangle];
     if (selectedRects.Where(x => x.Name == text).Any())
     {
​
     }
     else
     {
       SelectedRect selectedRect = new SelectedRect();
       selectedRect.Name = text;
       selectedRects.Add(selectedRect);
     }
​
   }
​
 }

现在再来看看最终的作用:

悉数代码

xaml:

<Window x:Class=""
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local=""
    xmlns:hc="https://handyorg.github.io/handycontrol"
    mc:Ignorable="d"
    Title="Drawing" Height="450" Width="800">
  <Window.Resources>
    <DataTemplate x:Key="MyTemplate">
      <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
  </Window.Resources>
  <StackPanel>
    <hc:Row Margin="0,20,0,0">
      <hc:Col Span="8">
        <Label Content="画矩形"></Label>
      </hc:Col>
      <hc:Col Span="8">
        <Button Style="{StaticResource ButtonPrimary}" Content="开端"
     Click="Button_Click_DrawRect"/>
      </hc:Col>
      <hc:Col Span="8">
        <Button Style="{StaticResource ButtonPrimary}" Content="清空"
            Click="Button_Click_Clear"/>
      </hc:Col>
    </hc:Row>
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>
​
      <Canvas Grid.Column="0" Background="Azure" x:Name="myCanvas1" Height="400">
        <!-- 在这里增加你的元素 -->
      </Canvas>
​
​
      <ListBox Grid.Column="1" SelectedIndex="0" Margin="10,0,10,0"
           ItemsSource="{Binding}"
           ItemTemplate="{StaticResource MyTemplate}">
        
      </ListBox>
    </Grid>
​
​
​
  </StackPanel>
</Window>
​

cs:

namespace xxx
{
  /// <summary>
  /// Drawing.xaml 的交互逻辑
  /// </summary>
  public partial class Drawing : System.Windows.Window
   {
    Dictionary<System.Windows.Shapes.Rectangle, string> rectangleText = new Dictionary<System.Windows.Shapes.Rectangle, string>();
    SelectedRects selectedRects;
    public Drawing()
     {
      InitializeComponent();
      this.selectedRects = new SelectedRects();
      DataContext = selectedRects;
​
     }
​
    private void Button_Click_DrawRect(object sender, RoutedEventArgs e)
     {
      int Row = 4;
      int Col = 3;
      
      for(int i = 0; i < Row; i++)
       {
        for(int j = 0; j< Col; j++) 
         {
          // 增加矩形
          System.Windows.Shapes.Rectangle rectangle = new System.Windows.Shapes.Rectangle
           {
            Width = 50,
            Height = 50,
            Stroke = System.Windows.Media.Brushes.Blue,
​
            // 设置填充色彩为通明色
            Fill = System.Windows.Media.Brushes.Transparent,
            StrokeThickness = 1
           };
​
          // 增加鼠标事情处理器,左键点击表明选中
          rectangle.MouseLeftButtonDown += Rectangle_MouseLeftButtonDown;
​
          // 增加鼠标事情处理器,右键点击表明撤销选中
          rectangle.MouseRightButtonDown += Rectangle_MouseRightButtonDown;
​
          Canvas.SetLeft(rectangle, 80 + 50 * j);
          Canvas.SetTop(rectangle, 50 + 50 * i);
         
          myCanvas1.Children.Add(rectangle);
​
          // 在矩形内部增加文字
          TextBlock textBlock = new TextBlock
           {
            Text = i + "-" + j,
            Foreground = System.Windows.Media.Brushes.Black,
            FontSize = 12
           };
​
          Canvas.SetLeft(textBlock, 80 + 50 * j + 10);
          Canvas.SetTop(textBlock, 50 + 50 * i + 10);
​
          myCanvas1.Children.Add(textBlock);
​
          // 将单元格与对应的信息存入字典
          rectangleText[rectangle] = textBlock.Text;
         }
        
       
       }
     
​
     }
​
    private void Button_Click_Clear(object sender, RoutedEventArgs e)
     {
      myCanvas1.Children.Clear();
     }
​
    // 鼠标事情处理器,左键点击表明选中
    private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
     {
      System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
      if (rectangle != null)
       {
        // 改动矩形的色彩以表明它被选中
        rectangle.Stroke = System.Windows.Media.Brushes.Red;
        string text = rectangleText[rectangle];
        if (selectedRects.Where(x => x.Name == text).Any())
         {
​
         }
        else
         {
          SelectedRect selectedRect = new SelectedRect();
          selectedRect.Name = text;
          selectedRects.Add(selectedRect);
         }
​
       }
​
     }
​
    // 鼠标事情处理器,右键点击表明选中
    private void Rectangle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
     {
      System.Windows.Shapes.Rectangle? rectangle = sender as System.Windows.Shapes.Rectangle;
      if (rectangle != null)
       {
        // 改动矩形的色彩以表明它被撤销选中
        rectangle.Stroke = System.Windows.Media.Brushes.Blue;
        string text = rectangleText[rectangle];
        var selectedRect = selectedRects.Where(x => x.Name == text).FirstOrDefault();
        if (selectedRect != null)
         {
          selectedRects.Remove(selectedRect);
         }
​
​
       }
​
     }
   }
}
​

总结

本文经过一个小示例,跟大家介绍了如何在WPF上制作矩形,并在其间增加文本,同时也介绍了ListBox的运用,经过数据绑定与数据模板显现咱们选中的单元格内的文本信息。期望对与我相同正在学习WPF或许对WPF感兴趣的同学有所帮助。